package com.grakol.parallel.samples.tests;

import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.Random;

import org.junit.Before;
import org.junit.Test;

import com.grakol.parallel.samples.IFunction;
import com.grakol.parallel.samples.MultiTaskLauncher;

/**
 * Runs simple sort test for integer arrays with 1 thread and 2 threads 
 * to compare results.
 * 
 * @author LK
 *
 */
public class TestSimpleSort {
	private int[] tArray1;
	private int[] tArray2;
	private IFunction<int[]> tFunction1;
	private IFunction<int[]> tFunction2;

	@Before
	public void setUp() {
		Random r = new Random();
		tArray1 = new int[100];
		tArray2 = new int[100];
		for( int i = 0; i < 100; i++ ) {
			tArray1[i] = r.nextInt( 10 ) % 2 == 0 ? i + 1 : 100 - i;
			tArray2[i] = r.nextInt( 10 ) % 2 != 0 ? i + 1 : 100 - i;
		}
		tFunction1 = new SimpleSortFunction( tArray1, 0, 100 );
		tFunction2 = new SimpleSortFunction( tArray2, 0, 100 );
	}
	
	@Test
	public void runFunction() {
		tFunction1.perform();
		tFunction2.perform();
		int[] result = tFunction1.mergeResults( Arrays.asList( tFunction1.getResult(), tFunction2.getResult() ) );
		assertTrue( result.length == 200 );
		boolean ordered = true;
		for( int i = 0; i < 199 && ordered; i++ )
			if( result[i] > result[i+1] ) 
				ordered = false;
		assertTrue( ordered );
	}
	
	/**
	 * @param args array_size
	 */
	public static void main(String[] args) {
		if( args.length < 1 ) {
			System.out.println( "usage: TestSimpleSort array_size" );
			return;
		}
		// generate int array
		int arraySize = Integer.valueOf( args[0] );
		int[] originalArray = new int[arraySize];
		Random random = new Random( System.currentTimeMillis() );
		for( int i = 0; i < arraySize; i++ )
			originalArray[i] = random.nextInt( arraySize );
		// test using current thread
		IFunction<int[]> function = new SimpleSortFunction( originalArray, 0, arraySize );
		long startTime = System.nanoTime();
		function.perform();
		int[] singleResult = function.getResult();
		long timeElapsedMs = (System.nanoTime() - startTime)/1000000;
		// print result for 1 thread
		System.out.println( "Single thread: Sort(" + arraySize + ") took " + timeElapsedMs + " ms" );
		// test using MultiTaskLauncher with 2 threads and 2 parts of the array
		int length1 = arraySize/2;
		int length2 = arraySize - length1;
		SimpleSortFunction[] functions = new SimpleSortFunction[2];
		functions[0] = new SimpleSortFunction( originalArray, 0, length1 );
		functions[1] = new SimpleSortFunction( originalArray, length1, length2 );
		MultiTaskLauncher<int[]> launcher = new MultiTaskLauncher<int[]>( functions  );
		// measure execution time
		startTime = System.nanoTime();
		launcher.start();
		int[] multiResult = launcher.getMergedResult();
		timeElapsedMs = (System.nanoTime() - startTime)/1000000;
		// print result for 2 threads
		System.out.println( "Two threads:   Sort(" + arraySize + ") took " + timeElapsedMs + " ms" );
		launcher.finish();
		// compare single- and multi-thread results
		if( singleResult.length != multiResult.length )
			System.err.println( "* 2 results have different length" );
		else {
			boolean same = true;
			for( int i = 0; i < singleResult.length; i++ )
				if( singleResult[i] != multiResult[i] ) {
					same = false;
					break;
				}
			if( ! same )
				System.err.println( "* 2 results are different" );
			else
				System.out.println( "* 2 results are the same" );
		}
	}

}
